package com.github.byakkili.bim.core.handler.connect;

import cn.hutool.core.collection.CollUtil;
import com.github.byakkili.bim.core.BimContext;
import com.github.byakkili.bim.core.protocol.Protocol;
import com.github.byakkili.bim.core.support.util.BimSessionUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

import static java.util.concurrent.TimeUnit.MILLISECONDS;

/**
 * 连接应答处理器
 *
 * @author Guannian Li
 */
@Slf4j
@Sharable
public class ConnectHandler extends SimpleChannelInboundHandler<ByteBuf> {
    private final int idleTimeout;
    /**
     * 协议列表
     */
    private final List<Protocol> protocols;

    public ConnectHandler(BimContext context) {
        super(false);
        this.idleTimeout = context.getConfig().getIdleTimeout();
        this.protocols = context.getConfig().getProtocols();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) {
        // 删除当前处理器
        ctx.pipeline().remove(this);
        // 获取协议提供者
        Protocol protocol = getCurrentProtocol(byteBuf);
        if (protocol == null) {
            if (log.isWarnEnabled()) {
                log.warn("Unsupported protocol type");
            }
            ctx.close().syncUninterruptibly();
        } else {
            Channel channel = ctx.channel();
            // 设置会话协议
            BimSessionUtils.get(channel).setProtocol(protocol.name());
            // 添加后续处理器
            channel.pipeline().addLast("server-idle-handler", new IdleStateHandler(0, 0, idleTimeout, MILLISECONDS));
            protocol.addPipeline(channel);
            // 继续往下执行处理器
            if (channel.isRegistered()) {
                channel.pipeline().fireChannelRegistered();
            }
            if (channel.isActive()) {
                channel.pipeline().fireChannelActive();
                channel.pipeline().fireChannelRead(byteBuf);
            }
        }
    }

    /**
     * 获取当前请求协议
     *
     * @param byteBuf 请求Buffer
     * @return 协议
     */
    private Protocol getCurrentProtocol(ByteBuf byteBuf) {
        for (Protocol protocol : CollUtil.emptyIfNull(protocols)) {
            if (protocol.canSupport(byteBuf)) {
                return protocol;
            }
        }
        return null;
    }
}
